<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-env.FeatureDetector'>/**
</span> * @class Ext.env.FeatureDetector
 */
Ext.define('Ext.env.FeatureDetector', {

    statics: {
        defaultTests: {
            Canvas: function() {
                var element = this.getTestElement('canvas');
                return !!(element &amp;&amp; element.getContext &amp;&amp; element.getContext('2d'));
            },
            SVG: function() {
                var doc = Ext.global.document;

                return !!(doc.createElementNS &amp;&amp; !!doc.createElementNS(&quot;http:/&quot; + &quot;/www.w3.org/2000/svg&quot;, &quot;svg&quot;).createSVGRect);
            },
            VML: function() {
                var element = this.getTestElement(),
                    ret = false;

                element.innerHTML = &quot;&lt;!--[if vml]&gt;&lt;br&gt;&lt;br&gt;&lt;![endif]--&gt;&quot;;
                ret = (element.childNodes.length === 2);
                element.innerHTML = &quot;&quot;;

                return ret;
            },
            Touch: function() {
                return ('ontouchstart' in Ext.global) &amp;&amp; !(Ext.platform &amp;&amp; Ext.platform.name.match(/Windows|MacOSX|Linux/));
            },
            Orientation: function() {
                return ('orientation' in Ext.global);
            },
            Geolocation: function() {
                return !!Ext.global.navigator.geolocation;
            },
            SqlDatabase: function() {
                return !!Ext.global.openDatabase;
            },
            Websockets: function() {
                return 'WebSocket' in Ext.global;
            },
            History: function() {
                return !!(Ext.global.history &amp;&amp; Ext.global.history.pushState);
            },
            CSSTransforms: function() {
                return this.isStyleSupported('transform');
            },
            CSS3DTransforms: function() {
                return this.has('csstransforms') &amp;&amp; this.isStyleSupported('perspective');
            },
            CSSAnimations: function() {
                return this.isStyleSupported('animationName');
            },
            CSSTransitions: function() {
                return this.isStyleSupported('transitionProperty');
            },
            Audio: function() {
                return !!this.getTestElement('audio').canPlayType;
            },
            Video: function() {
                return !!this.getTestElement('video').canPlayType;
            }
        },

        stylePrefixes: ['Webkit', 'Moz', 'O', 'ms']
    },

    constructor: function() {
        this.tests = {};

        this.testElements = {};

        this.registerTests(this.self.defaultTests, true);

        return this;
    },

    has: function(name) {
        if (!this.hasTest(name)) {
            return false;
        }
        else if (this.has.hasOwnProperty(name)) {
            return this.has[name];
        }
        else {
            return this.getTestResult(name);
        }
    },

    getTestResult: function(name) {
        return !!this.getTest(name).call(this);
    },

    getTestElement: function(tag) {
        if (!tag) {
            tag = 'div';
        }

        if (!this.testElements[tag]) {
            this.testElements[tag] = Ext.global.document.createElement(tag);
        }

        return this.testElements[tag];
    },

    registerTest: function(name, fn, isDefault) {
        //&lt;debug&gt;
        if (this.hasTest(name)) {
            Ext.Error.raise({
                sourceClass: &quot;Ext.env.FeatureDetector&quot;,
                sourceMethod: &quot;registerTest&quot;,
                msg: &quot;Test name &quot; + name + &quot; has already been registered&quot;
            });
        }
        //&lt;debug&gt;

        this.tests[name] = fn;

        if (isDefault) {
            this.has[name] = this.getTestResult(name);
        }

        return this;
    },

    registerTests: function(tests, isDefault) {
        Ext.Object.each(tests, function(name, fn) {
            this.registerTest(name, fn, isDefault);
        }, this);

        return this;
    },

    hasTest: function(name) {
        return this.tests.hasOwnProperty(name);
    },

    getTest: function(name) {
        //&lt;debug&gt;
        if (!this.hasTest(name)) {
            Ext.Error.raise({
                sourceClass: &quot;Ext.env.FeatureDetector&quot;,
                sourceMethod: &quot;getTest&quot;,
                msg: &quot;Test name &quot; + name + &quot; does not exist&quot;
            });
        }
        //&lt;debug&gt;

        return this.tests[name];
    },

    getTests: function() {
        return this.tests;
    },

    isStyleSupported: function(name, tag) {
        var elementStyle = this.getTestElement(tag).style,
            cName = Ext.String.capitalize(name),
            i = this.self.stylePrefixes.length;

        if (elementStyle[name] !== undefined) {
            return true;
        }

        while (i--) {
            if (elementStyle[this.self.stylePrefixes[i] + cName] !== undefined) {
                return true;
            }
        }

        return false;
    },

    isEventSupported: function(name, tag) {
        var element = this.getTestElement(tag),
            eventName = 'on' + name,
            isSupported = false;

        // When using `setAttribute`, IE skips &quot;unload&quot;, WebKit skips
        // &quot;unload&quot; and &quot;resize&quot;, whereas `in` &quot;catches&quot; those
        isSupported = (eventName in element);

        if (!isSupported) {
            if (element.setAttribute &amp;&amp; element.removeAttribute) {
                element.setAttribute(eventName, '');
                isSupported = typeof element[eventName] === 'function';

                // If property was created, &quot;remove it&quot; (by setting value to `undefined`)
                if (typeof element[eventName] !== 'undefined') {
                    element[eventName] = undefined;
                }

                element.removeAttribute(eventName);
            }
        }

        return isSupported;
    }

}, function() {

/*
 * Global convenient instance of {@link Ext.env.FeatureDetector Ext.env.FeatureDetector}
 * @member Ext features
 */
Ext.features = new Ext.env.FeatureDetector();

});
</pre></pre></body></html>